import java.util.ArrayList;

public class Solver implements Runnable {

	Sudoku sudoku;
	int speed;
	Thread thread;
	boolean solved;

	public Solver(Sudoku su, int sp) {
		sudoku = su;
		speed = sp;
		if (speed < 0)
			speed = 0;
		speed *= 200;
	}

	public void run() {
		while (!solved)
			oneLoop();
		System.out.println("SOLVED!!");
		sudoku.running = null;
		thread.stop();
	}
	
	private void oneLoop() {
		// update lil
		solved = true;
		for (int j = 0; j < 9; j++) {
			for (int i = 0; i < 9; i++) {
				sudoku.cursor.x = i;
				sudoku.cursor.y = j;
				if (sudoku.nums[i][j] > 0)
					continue;
				sudoku.lilNums[i][j] = getLil(i, j);
				//sleep();
				solved = false;
			}
		}
		// update big
		for (int j = 0; j < 9; j++) {
			for (int i = 0; i < 9; i++) {
				sudoku.cursor.x = i;
				sudoku.cursor.y = j;
				if (sudoku.nums[i][j] > 0)
					continue;
				/*if (sudoku.lilNums[i][j].size() == 0) {
					System.out.println("This Sudoku isn't solvable! :(");
					return;
				}*/
				if (sudoku.lilNums[i][j].size() == 1) {
					sudoku.nums[i][j] = (Integer) sudoku.lilNums[i][j].get(0);
					sudoku.lilNums[i][j].clear();
					//sleep();
				}
			}
		}
		//check for only one
	}
	private void sleep() {
		try {
			thread.sleep(speed);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	private ArrayList<Integer> getLil(int x, int y) {
		ArrayList<Integer> al = new ArrayList<Integer>();
		ArrayList<Integer> lx = getLilX(x);
		//System.out.println("x: "+lx);
		ArrayList<Integer> ly = getLilY(y);
		//System.out.println("y: "+ly);
		ArrayList<Integer> lb = getLilBox(x, y);

		for (int i = 1; i <= 9; i++) {
			if (lx.contains(i) && ly.contains(i) && lb.contains(i))
				al.add(i);
		}
		return al;
	}

	private ArrayList<Integer> getLilX(int x) {
		ArrayList<Integer> al = new ArrayList<Integer>();
		for (int i = 1; i <= 9; i++)
			al.add(i);

		for (int j = 0; j < 9; j++) {
			if (sudoku.nums[x][j] > 0)
				al.remove((Object) sudoku.nums[x][j]);
		}
		return al;
	}

	private ArrayList<Integer> getLilY(int y) {
		ArrayList<Integer> al = new ArrayList<Integer>();
		for (int i = 1; i <= 9; i++)
			al.add(i);

		for (int i = 0; i < 9; i++) {
			if (sudoku.nums[i][y] > 0)
				al.remove((Object) sudoku.nums[i][y]);
		}
		return al;
	}

	private ArrayList<Integer> getLilBox(int x, int y) {
		ArrayList<Integer> al = new ArrayList<Integer>();
		for (int i = 1; i <= 9; i++)
			al.add(i);
		// get Box
		int sx = 0, sy = 0;
		if (x > 5)
			sx = 6;
		else if (x > 2)
			sx = 3;
		if (y > 5)
			sy = 6;
		else if (y > 2)
			sy = 3;
		// check
		for (int i1 = 0, i = 0; i1 < 3; i1++) {
			for (int j = 0; j < 3; j++) {
				if (sudoku.nums[sx + i][sy + j] > 0)
					al.remove((Object) sudoku.nums[sx + i][sy + j]);
			}
			i++;
		}
		//System.out.println(sx + "x" + sy + " " + al);
		return al;
	}
}
